﻿Imports System.Globalization
Imports System.ComponentModel

Public Class UcCalendrier

    Public Enum ModeSelectionEnum
        Jour
        Semaine
        JourDansSemaine
    End Enum
    Private _ModeSelection As ModeSelectionEnum = ModeSelectionEnum.Jour
    <Category("My properties"), Description("Mode de selection")> _
    Public Property ModeSelection() As ModeSelectionEnum
        Get
            Return Me._ModeSelection
        End Get
        Set(ByVal Value As ModeSelectionEnum)

            Me._ModeSelection = Value

        End Set
    End Property

    Public Mois As Date = Date.Today.AddDays(-Date.Today.Day + 1)

    Private bmpMain As Bitmap = New Bitmap(100, 100)

    Private _Value As Date = Date.Today

    Public Property Value() As Date
        Get
            Return _Value
        End Get
        Set(ByVal value As Date)
            _Value = value
            RaiseEvent Value_Changed(Me, Nothing)
            SetIndexSemaine()
            Dessinner()
        End Set
    End Property

    Private _MonthLock As Boolean = False
    Public Property MonthLock() As Boolean
        Get
            Return _MonthLock
        End Get
        Set(ByVal value As Boolean)
            _MonthLock = value
            Btn_PrecMois.Enabled = Not value
            Btn_ProMois.Enabled = Not value
        End Set
    End Property
    Private _SelectionLock As Boolean = False
    Public Property SelectionLock() As Boolean
        Get
            Return _SelectionLock
        End Get
        Set(ByVal value As Boolean)
            _SelectionLock = value

        End Set
    End Property


    Public indexSemaine As Integer = 3
    Private cellW, cellH As Integer
    Private selectMois As Boolean = False
    Private surCellule As Point = New Point(-1, -1)
    Private loaded As Boolean = False

    Event Value_Changed As EventHandler

    Public Sub New()

        ' Cet appel est requis par le concepteur.
        InitializeComponent()

        ' Ajoutez une initialisation quelconque après l'appel InitializeComponent().
        '_Value = Date.Now
        SetSize()
    End Sub

    Private Sub UcCalendrier_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        If Not ModeSelection = ModeSelectionEnum.Jour Then
            _Value = _Value.AddDays(_Value.DayOfWeek)
        End If
        SetSize()
        SetIndexSemaine()
        Lbl_MoisAnnee.Text = StrConv(Mois.ToString("MMMM", CultureInfo.GetCultureInfo("fr-CA")), VbStrConv.ProperCase) + ", " + Mois.Year.ToString
        loaded = True
        Dessinner()
        Btn_PrecMois.BackgroundImage.RotateFlip(RotateFlipType.Rotate270FlipNone)
        Btn_ProMois.BackgroundImage.RotateFlip(RotateFlipType.Rotate90FlipNone)
    End Sub

    Private Sub Dessinner(Optional ByVal clear As Boolean = True)
        If Not loaded Then
            Return
        End If
        InitBitmap()
        Using g As Graphics = Graphics.FromImage(bmpMain)

            Dim rangee As Integer = 0
            Dim totalJour As Integer = Date.DaysInMonth(Mois.Year, Mois.Month)
            Dim totalSemaine As Integer = Convert.ToInt32(Math.Ceiling((totalJour + Mois.DayOfWeek) / 7))
            Dim formatTexte As New StringFormat()
            formatTexte.Alignment = StringAlignment.Center
            formatTexte.LineAlignment = StringAlignment.Center

            g.Clear(Color.White)

            'DESSINE LA GRILLE DE FOND
            'HORIZONTAL + ENTETE
            Dim cultureFran As Globalization.CultureInfo = CultureInfo.GetCultureInfo("fr-CA")
            For x As Integer = 0 To 7
                g.DrawLine(SystemPens.Control, New Point(x * cellW, 0), New Point(x * cellW, (totalSemaine + 1) * cellH))
                If x < 7 Then
                    g.DrawString(cultureFran.DateTimeFormat.GetDayName(x).Substring(0, 3), Me.Font, Brushes.Black, New Rectangle(x * cellW + 2, 0 * cellH, cellW, cellH), formatTexte)
                End If

            Next
            'VERTICAL
            For y As Integer = 0 To totalSemaine + 1
                g.DrawLine(SystemPens.Control, New Point(0, y * cellH), New Point(7 * cellW, y * cellH))
            Next



            formatTexte.Alignment = StringAlignment.Far

            'PLACE LES JOURS DU MOIS DANS LE CALENDRIER A LA BONNE PLACE
            For i As Integer = -Mois.DayOfWeek To totalJour - 1 + (7 - Mois.AddDays(totalJour).DayOfWeek)


                'SURLIGNE LA SEMAINE OU LE JOUR SELECTIONNÉ
                If JourDansDuree(Value, Mois.AddDays(-Mois.DayOfWeek), Mois.AddDays(totalJour - 1 + (7 - Mois.AddDays(totalJour).DayOfWeek))) Then

                    If ModeSelection = ModeSelectionEnum.Semaine Then
                        'DESSINNER SEULEMENT UN FOIS PAR RANGÉE (SEMAINE) LE PREMIER JOUR
                        If Mois.AddDays(i).DayOfWeek = 0 Then

                            If rangee = indexSemaine Then
                                g.FillRectangle(New SolidBrush(Color.FromArgb(200, 240, 255)), New Rectangle(0, (rangee + 1) * cellH, 7 * cellW, cellH))
                                g.DrawRectangle(Pens.Black, New Rectangle(0, (rangee + 1) * cellH, 7 * cellW, cellH))

                            End If

                        End If
                    ElseIf ModeSelection = ModeSelectionEnum.JourDansSemaine Then
                        'DESSINNER SEULEMENT UN FOIS PAR RANGÉE (SEMAINE) LE PREMIER JOUR
                        If Mois.AddDays(i).DayOfWeek = 0 Then

                            If rangee = indexSemaine Then
                                g.FillRectangle(New SolidBrush(Color.FromArgb(200, 240, 255)), New Rectangle(0, (rangee + 1) * cellH, 7 * cellW, cellH))
                            End If

                        End If
                        If Mois.AddDays(i).DayOfYear = Value.DayOfYear Then

                            g.DrawRectangle(Pens.Black, New Rectangle(Mois.AddDays(i).DayOfWeek * cellW, (rangee + 1) * cellH, cellW, cellH))
                        End If
                    Else
                        If Mois.AddDays(i).DayOfYear = Value.DayOfYear Then
                            g.FillRectangle(New SolidBrush(Color.FromArgb(200, 240, 255)), New Rectangle(Mois.AddDays(i).DayOfWeek * cellW, (rangee + 1) * cellH, cellW, cellH))
                            g.DrawRectangle(Pens.Black, New Rectangle(Mois.AddDays(i).DayOfWeek * cellW, (rangee + 1) * cellH, cellW, cellH))
                        End If
                    End If
                End If


                If Mois.AddDays(i).Month = Mois.Month Then
                    If Mois.AddDays(i) = Date.Today Then
                        g.FillRectangle(New SolidBrush(Color.FromArgb(100, 180, 200, 255)), New Rectangle(Mois.AddDays(i).DayOfWeek * cellW + 1, (rangee + 1) * cellH + 1, cellW - 1, cellH - 1))
                    End If

                    g.DrawString((Mois.AddDays(i).Day).ToString, Me.Font, Brushes.Black, New Rectangle(Mois.AddDays(i).DayOfWeek * cellW, (rangee + 1) * cellH, cellW - 2, cellH), formatTexte)
                Else
                    g.DrawString((Mois.AddDays(i).Day).ToString, Me.Font, Brushes.Gray, New Rectangle(Mois.AddDays(i).DayOfWeek * cellW, (rangee + 1) * cellH, cellW - 2, cellH), formatTexte)
                End If

                If Mois.AddDays(i).DayOfWeek = 6 Then

                    rangee += 1
                End If

            Next
            'SURLIGNE LA SEMAINE OU JOURNÉE SOUS LE CURSEUR
            If surCellule.Y <> -1 And Not (ModeSelection = ModeSelectionEnum.Semaine And SelectionLock) Then
                If ModeSelection = ModeSelectionEnum.Semaine Then
                    If Not (surCellule.Y = indexSemaine And JourDansDuree(Value, Mois.AddDays(-Mois.DayOfWeek), Mois.AddDays(totalJour - 1 + (7 - Mois.AddDays(totalJour).DayOfWeek)))) Then
                        g.DrawRectangle(Pens.Gray, New Rectangle(0, (surCellule.Y + 1) * cellH, 7 * cellW, cellH))
                    End If
                ElseIf ModeSelection = ModeSelectionEnum.JourDansSemaine Then
                    If surCellule.Y = indexSemaine And surCellule.X <> Value.DayOfWeek Then
                        g.DrawRectangle(Pens.Gray, New Rectangle(surCellule.X * cellW, (surCellule.Y + 1) * cellH, cellW, cellH))
                    End If
                Else
                    g.DrawRectangle(Pens.Gray, New Rectangle(surCellule.X * cellW, (surCellule.Y + 1) * cellH, cellW, cellH))
                End If
            End If

        End Using
        Using g As Graphics = Me.CreateGraphics()
            If clear Then
                g.Clear(Color.White)
            End If
            If Not Tlp_SelectMois.Visible Then
                g.DrawImageUnscaled(bmpMain, 1, Tlp_Controles.Height + Tlp_Controles.Location.Y)
            End If

        End Using
    End Sub

    Private Sub UcCalendrier_Resize(sender As System.Object, e As System.EventArgs) Handles MyBase.Resize
        bmpMain.Dispose()
        SetSize()
        InitBitmap()

        Dessinner()
        Tlp_SelectMois.Height = Me.Height - Tlp_Controles.Height

    End Sub

    Private Sub InitBitmap()
        Dim totalJour As Integer = Date.DaysInMonth(Mois.Year, Mois.Month)
        Dim totalSemaine As Integer = Convert.ToInt32(Math.Ceiling((totalJour + Mois.DayOfWeek) / 7))
        bmpMain = New Bitmap(Convert.ToInt32(cellW * 7 + 1), Convert.ToInt32((totalSemaine + 1) * cellH + 1))
    End Sub

    Private Sub UcCalendrier_Paint(sender As System.Object, e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
        e.Graphics.Clear(Color.White)
        If Not Tlp_SelectMois.Visible Then
            e.Graphics.DrawImageUnscaled(bmpMain, 1, Tlp_Controles.Height + Tlp_Controles.Location.Y)
        End If



    End Sub

    Private Sub SetIndexSemaine()

        Dim rangee As Integer = 0
        Dim totalJour As Integer = Date.DaysInMonth(Mois.Year, Mois.Month)

        For i As Integer = -Mois.DayOfWeek To totalJour - 1 + (7 - Mois.AddDays(totalJour).DayOfWeek)

            If Mois.AddDays(i).DayOfYear = Value.DayOfYear Then
                indexSemaine = rangee
                Return

            End If
            If Mois.AddDays(i).DayOfWeek = 6 Then
                rangee += 1
            End If
        Next
    End Sub

    Private Function GetDateOfWeek(ByVal ind) As Date
        Dim rangee As Integer = 0
        Dim totalJour As Integer = Date.DaysInMonth(Mois.Year, Mois.Month)

        For i As Integer = -Mois.DayOfWeek To totalJour - 1 + (7 - Mois.AddDays(totalJour).DayOfWeek)

            If rangee = ind Then
                If Mois.AddDays(i).DayOfWeek = 0 Then
                    'Console.WriteLine("date of week " + Mois.AddDays(i).ToString())
                    Return Mois.AddDays(i)
                End If
            End If
            If Mois.AddDays(i).DayOfWeek = 6 Then
                rangee += 1
            End If
        Next
        Return Date.Today
    End Function

    Private Sub Lbl_MoisAnneeMouseHover(sender As System.Object, e As System.EventArgs) Handles Lbl_MoisAnnee.MouseHover
        If Not selectMois Then
            Cursor = Cursors.Hand
        End If

    End Sub

    Private Sub Lbl_MoisAnnee_MouseLeave(sender As System.Object, e As System.EventArgs) Handles Lbl_MoisAnnee.MouseLeave
        Cursor = Cursors.Default
    End Sub


    Private Sub Lbl_MoisAnnee_Click(sender As System.Object, e As System.EventArgs) Handles Lbl_MoisAnnee.Click
        If Not selectMois And Not MonthLock And Not SelectionLock Then
            selectMois = True
            Lbl_MoisAnnee.Text = Mois.Year.ToString
            Tlp_SelectMois.Visible = True
            Dessinner(True)
            For Each ctrl As Control In Tlp_SelectMois.Controls
                If ctrl.TabIndex = Mois.Month - 1 Then
                    ctrl.Focus()
                    Exit For
                End If
            Next
        End If

    End Sub

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Btn_PrecMois.Click
        If Not selectMois Then
            Mois = Mois.AddMonths(-1)
            'Value = Mois
            SetIndexSemaine()

            Dessinner()
            Lbl_MoisAnnee.Text = StrConv(Mois.ToString("MMMM", CultureInfo.GetCultureInfo("fr-CA")), VbStrConv.ProperCase) + ", " + Mois.Year.ToString
        Else
            Mois = Mois.AddYears(-1)
            Lbl_MoisAnnee.Text = Mois.Year.ToString
        End If
    End Sub

    Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Btn_ProMois.Click
        If Not selectMois Then
            Mois = Mois.AddMonths(1)
            'Value = Mois
            SetIndexSemaine()

            Dessinner()
            Lbl_MoisAnnee.Text = StrConv(Mois.ToString("MMMM", CultureInfo.GetCultureInfo("fr-CA")), VbStrConv.ProperCase) + ", " + Mois.Year.ToString
        Else
            Mois = Mois.AddYears(1)
            Lbl_MoisAnnee.Text = Mois.Year.ToString

        End If
    End Sub

    Private Sub Btn_Mois_Clicked(sender As System.Object, e As System.EventArgs) Handles Button4.Click, Btn_sept.Click, Btn_Oct.Click, Btn_Nov.Click, Btn_Mai.Click, Btn_Juin.Click, Btn_Juil.Click, Btn_Janv.Click, Btn_Fevr.Click, Btn_Dec.Click, Btn_avr.Click, Btn_Aout.Click
        Dim indexMois As Integer = Tlp_SelectMois.GetCellPosition(sender).Row * 4 + Tlp_SelectMois.GetCellPosition(sender).Column
        selectMois = False
        Tlp_SelectMois.Visible = False

        Mois = Mois.AddMonths(-Mois.Month + 1 + indexMois)
        Value = Mois
        Dessinner()
        Lbl_MoisAnnee.Text = StrConv(Mois.ToString("MMMM", CultureInfo.GetCultureInfo("fr-CA")), VbStrConv.ProperCase) + ", " + Mois.Year.ToString

    End Sub

    Private Sub UcCalendrier_FontChanged(sender As System.Object, e As System.EventArgs) Handles MyBase.FontChanged
        SetSize()
    End Sub

    Private Sub SetSize()
        Dim cellSize As SizeF
        Using g As Graphics = Me.CreateGraphics()
            cellSize = g.MeasureString("sam", Me.Font)
        End Using
        cellW = cellSize.Width + 5
        cellH = cellSize.Height + 5
        Me.Size = New Size(7 * cellW + 5, Tlp_Controles.Height + cellH * 7 + 5)
        Tlp_SelectMois.Height = Me.Height - Tlp_Controles.Height - cellH
        Tlp_SelectMois.Dock = DockStyle.Top
    End Sub

    Private Sub UcCalendrier_MouseMove(sender As System.Object, e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseMove
        If e.Location.Y > Tlp_Controles.Height + Tlp_Controles.Location.Y Then
            Dim totalJour As Integer = Date.DaysInMonth(Mois.Year, Mois.Month)
            Dim totalSemaine As Integer = Convert.ToInt32(Math.Ceiling((totalJour + Mois.DayOfWeek) / 7))
            Dim newpos As Point = New Point(Math.Floor(e.Location.X / cellW), Math.Floor((e.Location.Y - (Tlp_Controles.Height + Tlp_Controles.Location.Y)) / cellH) - 1)
            If newpos.Y = -1 Or newpos.Y >= totalSemaine Then
                surCellule = New Point(-1, -1)
                Dessinner(False)
                Return
            End If
            If Not surCellule = newpos Then
                surCellule = newpos
                Dessinner(False)
            Else

            End If
        Else
            surCellule = New Point(-1, -1)
        End If
    End Sub

    Private Sub UcCalendrier_MouseClick(sender As System.Object, e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseClick
        If selectMois Then
            selectMois = False
            Tlp_SelectMois.Visible = False

            Dessinner()
            Lbl_MoisAnnee.Text = StrConv(Mois.ToString("MMMM", CultureInfo.GetCultureInfo("fr-CA")), VbStrConv.ProperCase) + ", " + Mois.Year.ToString
            Return
        End If
        If ModeSelection = ModeSelectionEnum.Semaine And SelectionLock Then
            Return
        End If
        If surCellule.Y <> -1 And Not selectMois Then
            If _ModeSelection = ModeSelectionEnum.Semaine Then
                Value = GetDateOfWeek(surCellule.Y)
                Dessinner(False)
            ElseIf ModeSelection = ModeSelectionEnum.JourDansSemaine Then
                If surCellule.Y = indexSemaine Then
                    Value = GetDateOfWeek(surCellule.Y).AddDays(surCellule.X)
                    Dessinner(False)
                End If
            Else
                Value = GetDateOfWeek(surCellule.Y).AddDays(surCellule.X)
                Dessinner(False)
            End If
        End If
    End Sub

    Private Sub UcCalendrier_MouseLeave(sender As System.Object, e As System.EventArgs) Handles MyBase.MouseLeave
        surCellule = New Point(-1, -1)
        Dessinner(False)
    End Sub

    Private Function JourDansDuree(ByVal jour As Date, ByVal debut As Date, ByVal fin As Date) As Boolean
        Return (debut <= jour And jour <= fin)
    End Function

    Public Sub ChangerMois(ByVal nMois As Date)
        Mois = nMois
        Lbl_MoisAnnee.Text = StrConv(Mois.ToString("MMMM", CultureInfo.GetCultureInfo("fr-CA")), VbStrConv.ProperCase) + ", " + Mois.Year.ToString
        Dessinner()
    End Sub

    Private Sub Tlp_SelectMois_Click(sender As System.Object, e As System.EventArgs) Handles Tlp_SelectMois.Click, Tlp_Controles.Click
        selectMois = False
        Tlp_SelectMois.Visible = False

        Dessinner()
        Lbl_MoisAnnee.Text = StrConv(Mois.ToString("MMMM", CultureInfo.GetCultureInfo("fr-CA")), VbStrConv.ProperCase) + ", " + Mois.Year.ToString
    End Sub

    Public Sub GoToValue()
        Mois = Value.AddDays(-Value.Day + 1)
        SetIndexSemaine()

        Dessinner()
        Lbl_MoisAnnee.Text = StrConv(Mois.ToString("MMMM", CultureInfo.GetCultureInfo("fr-CA")), VbStrConv.ProperCase) + ", " + Mois.Year.ToString
    End Sub

    Private Sub Tlp_SelectMois_VisibleChanged(sender As System.Object, e As System.EventArgs) Handles Tlp_SelectMois.VisibleChanged
        If Tlp_SelectMois.Visible Then
            Tlp_SelectMois.Height = Me.Height - Tlp_Controles.Height - cellH
        End If

    End Sub
End Class
